using System;
using System.Collections.Generic;
using System.Text;
using CookComputing.XmlRpc;
using BlogLib;
using System.Diagnostics;

namespace CommonLibrary
{
	public class WordPressClient : MovableTypeInterface
	{
		#region Private Fields
		
		private WordPressXmlRpcClient _wpXmlRpc;
		private string _blogId;
		private string _username;
		private string _password;
		private SortedList<string, Category> _categories;

		#endregion

		#region Constructors

		/// <summary>
		/// Create a connection to a particular WordPress blog
		/// </summary>
		/// <param name="url">The url of the XML-RPC script on the server</param>
		/// <param name="blogId">The id number of the blog</param>
		/// <param name="username">Admin username</param>
		/// <param name="password">Admin password</param>
		public WordPressClient(string url, string blogId, string username, string password) : base(url)
		{
			base.xrInterface.NonStandard = CookComputing.XmlRpc.XmlRpcNonStandard.AllowNonStandardDateTime;
			_wpXmlRpc = new WordPressXmlRpcClient();
			_wpXmlRpc.Url = url;

			_blogId = blogId;
			_username = username;
			_password = password;;
		}

		#endregion

		#region Private Methods

		/// <summary>
		/// Convert a different post type into a MovableType post object
		/// </summary>
		/// <param name="post"></param>
		/// <returns></returns>
		private MovableTypeInterface.Post ConvertToMtPost(Post post)
		{
			MovableTypeInterface.Post mtPost = new MovableTypeInterface.Post();
			mtPost.dateCreated = post.dateCreated;
			mtPost.description = post.description;
			mtPost.mt_allow_comments = post.allowComments;
			mtPost.mt_allow_pings = post.allowPings;
			mtPost.mt_convert_breaks = "1";
			mtPost.mt_excerpt = post.excerpt;
			mtPost.mt_keywords = post.keywords;
			mtPost.mt_text_more = post.textMore;
			mtPost.title = post.title;

			return mtPost;
		}

		/// <summary>
		/// Converts a different type of post object to a WordPressClient.Post object
		/// </summary>
		/// <param name="mtPost"></param>
		/// <returns></returns>
		private Post ConvertToWpPost(MovableTypeInterface.PostInfo mtPost)
		{
			Post post = new Post();
			post.allowComments = mtPost.mt_allow_comments;
			post.allowPings = mtPost.mt_allow_pings;
			post.dateCreated = mtPost.dateCreated;
			post.description = mtPost.description;
			post.excerpt = mtPost.mt_excerpt;
			post.keywords = mtPost.mt_excerpt;
			post.link = mtPost.link;
			post.permaLink = mtPost.permaLink;
			post.textMore = mtPost.mt_text_more;
			post.title = mtPost.title;
			post.userid = mtPost.userid;

			return post;
		}

		#endregion

		#region Public Methods

		/// <summary>
		/// Delete the post with the given post id
		/// </summary>
		/// <param name="postId"></param>
		/// <param name="publish"></param>
		/// <returns></returns>
		public bool DeletePost(string postId, bool publish)
		{
			return DeletePost(postId, Username, Password, publish);
		}

		/// <summary>
		/// Return a list of the specified number of recent posts
		/// </summary>
		/// <param name="numberOfPosts"></param>
		/// <returns></returns>
		public List<Post> GetRecentPosts(int numberOfPosts)
		{
			List<Post> list = new List<Post>();

			foreach (PostInfo post in GetRecentPosts(BlogId, Username, Password, numberOfPosts))
			{
				list.Add(ConvertToWpPost(post));
			}

			return list;
		}

		/// <summary>
		/// Create a new post
		/// </summary>
		/// <param name="title"></param>
		/// <param name="body"></param>
		/// <param name="createDate"></param>
		/// <param name="publish"></param>
		/// <returns>The new post id on the blog</returns>
		public string NewPost(string title, string body, DateTime createDate, bool publish)
		{
			return NewPost(BlogId, Username, Password, title, body, createDate.ToUniversalTime(), publish);
		}

		/// <summary>
		/// Get the post specified
		/// </summary>
		/// <param name="postId"></param>
		/// <returns></returns>
		public Post GetPost(string postId)
		{
			return ConvertToWpPost(GetPost(postId, Username, Password));
		}

		/// <summary>
		/// Update a post with the passed in values
		/// </summary>
		/// <param name="postId">The id of the post to update</param>
		/// <param name="post">The new post values to update</param>
		/// <param name="publish">If true publish the post, if false mark it as draft</param>
		public bool EditPost(Post post, bool publish)
		{
			return EditPost(post.postid, Username, Password, ConvertToMtPost(post), publish);
		}

		/// <summary>
		/// Return a list of the custom field keys for a post
		/// </summary>
		/// <param name="postId"></param>
		/// <returns></returns>
		public List<string> GetPostCustomFieldKeys(string postId)
		{
			return new List<string>(_wpXmlRpc.GetPostCustomFieldKeys(postId, Username, Password));
		}

		/// <summary>
		/// Assign a custom field value to a post
		/// </summary>
		/// <param name="postId"></param>
		/// <param name="key"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		public bool SetPostCustomField(string postId, string key, string value)
		{
			return _wpXmlRpc.SetPostCustomField(postId, Username, Password, key, value);
		}

		/// <summary>
		/// Get a list of the categories for the specified post
		/// </summary>
		/// <param name="postId"></param>
		/// <returns></returns>
		public List<Category> GetPostCategories(string postId)
		{
			List<Category> list = new List<Category>();
			PostCategory[] postcats = GetPostCategories(postId, Username, Password);
			foreach (PostCategory cat in postcats)
			{
				list.Add(Categories[cat.categoryName.ToUpper()]);
			}
			return list;
		}

		/// <summary>
		/// Get a custom field for the specified post
		/// </summary>
		/// <param name="postId"></param>
		/// <param name="key"></param>
		/// <returns></returns>
		public object GetPostCustomField(string postId, string key)
		{
			return _wpXmlRpc.GetPostCustomFieldValue(postId, Username, Password, key);
		}

		/// <summary>
		/// Create a new category on the blog
		/// </summary>
		/// <param name="category">The category object to create</param>
		/// <returns>The category id</returns>
		public int NewCategory(Category category)
		{
			return _wpXmlRpc.NewCategory(BlogId, Username, Password, category);
		}

		/// <summary>
		/// Assign a list of categories to the specified post
		/// </summary>
		/// <param name="postId"></param>
		/// <param name="categories"></param>
		public void SetPostCategories(string postId, List<Category> categories)
		{
			List<SetPostCategory> cats = new List<SetPostCategory>(categories.Count);
			foreach (Category category in categories)
			{
				SetPostCategory newcat = new SetPostCategory();
				newcat.categoryId = category.categoryId;
				cats.Add(newcat);
			}

			SetPostCategories(postId, Username, Password, cats.ToArray()); 
		}

		#endregion

		#region Properties

		public string[] SupportedMethods
		{
			get { return GetSupportedMethods(); }
		}

		public SortedList<string, Category> Categories
		{
			get
			{
				if (_categories == null)
				{
					_categories = new SortedList<string, Category>();
					foreach (Category cat in _wpXmlRpc.GetBlogCategories(BlogId, Username, Password))
					{
						_categories.Add(cat.categoryName.ToUpper(), cat);
					}
				}

				return _categories;
			}
		}

		public string BlogId
		{
			get { return _blogId; }
		}

		public string Username
		{
			get { return _username; }
		}

		public string Password
		{
			get { return _password; }
		}

		#endregion

		#region Struts

		public new struct Post
		{
			public DateTime dateCreated;
			public string description;
			public string link;
			public int allowComments;
			public int allowPings;
			public string excerpt;
			public string keywords;
			public string textMore;
			public string permaLink;
			public string postid;
			public string title;
			public string userid;
		}

		[DebuggerDisplay("{categoryName}")]
		public new struct Category
		{
			public string parentId;
			public string categoryId;
			public string rssUrl;
			public string description;
			public string htmlUrl;
			public string categoryName;
		}

		#endregion

		#region Internal XmlRpcClass

		private class WordPressXmlRpcClient : CookComputing.XmlRpc.XmlRpcClientProtocol
		{
			[XmlRpcMethod("wp.getCategories")]
			public Category[] GetBlogCategories(string blogid, string username, string password)
			{
				return (Category[])this.Invoke("GetBlogCategories", new object[] { blogid, username, password });
			}

			[XmlRpcMethod("wp.newCategory")]
			public int NewCategory(string blogid, string username, string password, Category category)
			{
				return (int)this.Invoke("NewCategory", new object[] { blogid, username, password, category });
			}

			[XmlRpcMethod("wpext.setPostCustomField")]
			public bool SetPostCustomField(string postid, string username, string password, string fieldkey, string fieldvalue)
			{
				return (bool)this.Invoke("SetPostCustomField", new object[] { postid, username, password, fieldkey, fieldvalue });
			}

			[XmlRpcMethod("wpext.getPostCustomFieldKeys")]
			public string[] GetPostCustomFieldKeys(string postid, string username, string password)
			{
				return (string[])this.Invoke("GetPostCustomFieldKeys", new object[] { postid, username, password });
			}

			[XmlRpcMethod("wpext.getPostCustomFieldValue")]
			public object GetPostCustomFieldValue(string postid, string username, string password, string fieldkey)
			{
				return (object)this.Invoke("GetPostCustomFieldValue", new object[] { postid, username, password, fieldkey });
			}
		}

		#endregion
	}
}
